package com.zmn.oms.zmn.business.impl.redistribute;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.zmn.base.common.data.common.dro.tags.TagsDRO;
import com.zmn.base.common.data.common.query.tags.TagsQuery;
import com.zmn.base.common.data.dubbo.interfaces.tags.TagsListRemoteService;
import com.zmn.base.engineer.common.dro.foreign.engineer.ForeignEngineerMobileInfoDRO;
import com.zmn.base.engineer.common.dro.supervisor.SupervisorDetailDRO;
import com.zmn.base.engineer.dubbo.interfaces.foreign.EngineerListRemoteService;
import com.zmn.base.engineer.dubbo.interfaces.supervisor.EngineerSupervisorListRemoteService;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWork;
import com.zmn.base.pilot.common.dto.pilot.PilotCheckQuery;
import com.zmn.base.pilot.common.enums.PilotTypeEnum;
import com.zmn.base.pilot.dubbo.interfaces.pilot.PilotRemoteService;
import com.zmn.base.plat.engine.common.constant.DubboConsts;
import com.zmn.base.product.common.consts.BaseProductConsts;
import com.zmn.base.product.common.dto.product.ProductBaseQuery;
import com.zmn.base.product.common.dto.product.ec.ProductBaseDRO;
import com.zmn.base.product.dubbo.interfaces.product.foreign.ProductForeignListRemoteService;
import com.zmn.common.dto2.AMISListData;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.common.utils.BaiduMapUtil;
import com.zmn.manager.redis.RedisManager;
import com.zmn.mcc.common.constant.StaffConsts;
import com.zmn.mcc.common.dto.staff.StaffDRO;
import com.zmn.mcc.dubbo.interfaces.staff.StaffListRemoteService;
import com.zmn.oms.business.interfaces.base.BaseCodeService;
import com.zmn.oms.business.interfaces.conf.distributereason.ConfOrderDistributeReasonBService;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import com.zmn.oms.business.interfaces.work.OrderWorkListBService;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dio.redistribute.CheckApplyRedistributeDIO;
import com.zmn.oms.common.dio.redistribute.EngineerRedistributeQuery;
import com.zmn.oms.common.dio.redistribute.OrderWorkRedistributeApplyQuery;
import com.zmn.oms.common.dio.redistribute.RedistributeWorkQuery;
import com.zmn.oms.common.dio.redistribute.audit.ManagerAuditQuery;
import com.zmn.oms.common.dro.redistribute.EngineerDRO;
import com.zmn.oms.common.dro.redistribute.EngineerWorkRedistributeDRO;
import com.zmn.oms.common.dro.redistribute.OrderWorkRedistributeStatusDRO;
import com.zmn.oms.common.dro.redistribute.audit.ApplyDetailDRO;
import com.zmn.oms.common.dro.redistribute.audit.ApplyItemDRO;
import com.zmn.oms.common.dro.redistribute.audit.ApplyRedistributeDetailDRO;
import com.zmn.oms.common.dro.redistribute.audit.ApplyWorkDetailDRO;
import com.zmn.oms.common.enums.*;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.utils.MobileUtil;
import com.zmn.oms.model.bo.conf.distribute.reason.ConfOrderDistributeReasonBO;
import com.zmn.oms.model.bo.redistribute.CheckApplyRedistributeBO;
import com.zmn.oms.model.bo.redistribute.CheckOperateBO;
import com.zmn.oms.model.dto.redistribute.RedistributeAttachmentDTO;
import com.zmn.oms.model.entity.changerecord.OrderChangeRecord;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.product.OrderProduct;
import com.zmn.oms.model.entity.redistribute.OrderWorkRedistributeApply;
import com.zmn.oms.model.entity.redistribute.OrderWorkRedistributeInfo;
import com.zmn.oms.model.entity.redistribute.OrderWorkRedistributeMaster;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkQuery;
import com.zmn.oms.model.vo.work.ZsOrderDistributeVO;
import com.zmn.oms.services.interfaces.changerecord.OrderChangeRecordService;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.orderencrypt.OrderEncryptService;
import com.zmn.oms.services.interfaces.product.OrderProductService;
import com.zmn.oms.services.interfaces.redistribute.OrderWorkRedistributeApplyService;
import com.zmn.oms.services.interfaces.redistribute.OrderWorkRedistributeInfoService;
import com.zmn.oms.services.interfaces.redistribute.OrderWorkRedistributeMasterService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.zmn.business.interfaces.redistribute.OrderWorkRedistributeListBService;
import com.zmn.oms.zmn.business.interfaces.work.customwork.ZsDistributeWorkBService;
import com.zmn.sp.common.model.dro.SpRedistributeDRO;
import com.zmn.sp.common.model.manage.SpServProviderDetailDRO;
import com.zmn.sp.dubbo.interfaces.manage.SpManageListRemoteService;
import com.zmn.track.common.constant.apply.cancel.CancelApplyConsts;
import com.zmn.track.dubbo.dio.apply.cancel.OrderCancelApplyQuery;
import com.zmn.track.dubbo.dro.apply.cancel.OrderCancelApplyDRO;
import com.zmn.track.dubbo.interfaces.apply.cancel.OrderCancelApplyListRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author sunlife
 * @date:2022/5/9 下午4:44
 * description: 工单改派查询业务类
 */
@Slf4j
@Service
public class OrderWorkRedistributeListBServiceImpl implements OrderWorkRedistributeListBService {

    @Autowired
    OrderWorkService orderWorkService;
    @Autowired
    OrderWorkListBService orderWorkListBService;
    @Autowired
    OrderDetailService orderDetailService;
    @Autowired
    OrderProductService orderProductService;
    @Autowired
    OrderWorkRedistributeApplyService orderWorkRedistributeApplyService;
    @Autowired
    OrderWorkRedistributeInfoService orderWorkRedistributeInfoService;
    @Autowired
    OrderWorkRedistributeMasterService orderWorkRedistributeMasterService;
    @Autowired
    OrderChangeRecordService orderChangeRecordService;
    @Autowired
    OrderEncryptService orderEncryptService;
    @Autowired
    ZsDistributeWorkBService zsDistributeWorkBService;
    @Autowired
    ConfOrderDistributeReasonBService confOrderDistributeReasonBService;
    @Autowired
    RedisManager redisManager;
    @Autowired
    BaseCodeService baseCodeService;
    @Autowired
    OrderWorkEsBService orderWorkEsBService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    TagsListRemoteService tagsListRemoteService;
    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    EngineerListRemoteService engineerListRemoteService;
    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    StaffListRemoteService staffListRemoteService;
    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    SpManageListRemoteService spManageListRemoteService;
    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    OrderCancelApplyListRemoteService orderCancelApplyListRemoteService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    EngineerSupervisorListRemoteService engineerSupervisorListRemoteService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    PilotRemoteService pilotRemoteService;

    @DubboReference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    protected ProductForeignListRemoteService productForeignListRemoteService;

    @Override
    public CheckOperateBO checkCanOperateRedistribute(Long orderId, Long workId) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (orderWork == null) {
            throw new OmsBaseException(OmsErrorCodeConsts.ORDER_NOT_FOUND, "订单不存在");
        }

        CheckOperateBO result = new CheckOperateBO();

        do {
            result.setDistributeWay(orderWork.getDistributeWay());

            result.setCanOperate(GlobalConsts.NO);

            // 是否试点
            PilotCheckQuery checkQuery = PilotCheckQuery.builder()
                    .channelId(orderWork.getChannelId())
                    .cityId(orderWork.getCityId())
                    .servCategId(orderWork.getServCategId())
                    .categId(orderWork.getShowCategId())
                    .pilotTypeId(PilotTypeEnum.ORDER_REASSIGNMENT.getId()).build();

            ResponseDTO<Boolean> checkResponse = pilotRemoteService.checkPilotByQuery(checkQuery);
            log.info("获取试点配置 rucan :{}, 出参：{}", JSON.toJSONString(checkQuery), JSON.toJSONString(checkResponse));
            if (!checkResponse.isSuccess()) {
                result.setMessage("无法获取试点配置信息，请稍后重试");
                break;
            }
            if (checkResponse.getData()) {
                // 是试点
                result.setIsPilot(GlobalConsts.YES);
            } else {
                result.setIsPilot(GlobalConsts.NO);
            }

            // 查询该订单是否有【待审核/处理中】的“取消”申请
            OrderCancelApplyQuery orderCancelApplyQuery = new OrderCancelApplyQuery();
            orderCancelApplyQuery.setOrderId(orderId);
            orderCancelApplyQuery.setWorkId(workId);
            orderCancelApplyQuery.setReviewStatusList(Lists.newArrayList(CancelApplyConsts.ORDER_REVIEW_STATUS_CHECK, CancelApplyConsts.ORDER_REVIEW_STATUS_CHECK_PROCESSING));
            ResponseDTO<List<OrderCancelApplyDRO>> cancelApplyResponseDTO = orderCancelApplyListRemoteService.listCancelApplyByQuery(orderCancelApplyQuery);
            if (log.isDebugEnabled()) {
                log.debug("根据条件查询取消申请#listCancelApplyByQuery 入参：{} listResponseDTO={}", orderCancelApplyQuery, cancelApplyResponseDTO);
            }

            if (cancelApplyResponseDTO.isSuccess() && CollectionUtil.isNotNullOrEmpty(cancelApplyResponseDTO.getData())) {
                result.setHasCancelApply(GlobalConsts.YES);
            } else {
                result.setHasCancelApply(GlobalConsts.NO);
            }


            // 平台直派才可以操作
            if (!Objects.equals(orderWork.getDistributeWay(), OrderDistributeConsts.DISTRIBUTE_WAY_PLAT)) {
                result.setMessage("非平台直派订单，不可操作");
                break;
            }

            if (!checkResponse.getData()) {
                result.setMessage("试点未开通");
                break;
            }

            if (orderWork.getStatus() < OrderStatusConsts.WORK_STATUS_TAKE || orderWork.getStatus() >= OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE) {
                result.setMessage("订单状态不正确，不可操作！");
                break;
            }

            String message = this.verifyWorkStatusForRedistribute(orderWork, GlobalConsts.OPERATE_USER_TYPE_MASTER);
            if (StringUtils.isNotBlank(message)) {
                result.setMessage(message);
                break;
            }
            // 查询进行中的改派申请
            OrderWorkRedistributeApplyQuery query = new OrderWorkRedistributeApplyQuery();
            query.setOrderId(orderWork.getOrderId());
            query.setWorkId(orderWork.getWorkId());
            query.setRedistributeStatus(RedistributeStatusEnum.WAIT_REDISTRIBUTE.getCode());
            List<OrderWorkRedistributeApply> applyList = orderWorkRedistributeApplyService.listByQuery(query);
            if (CollectionUtil.isNotNullOrEmpty(applyList)) {
                result.setMessage("不可重复发起！");
                break;
            }

            result.setCanOperate(GlobalConsts.YES);
            break;
        } while (true);

        return result;
    }


    @Override
    public CheckApplyRedistributeBO checkCanApplyRedistribute(CheckApplyRedistributeDIO checkApplyRedistributeDIO) throws OmsBaseException  {

        CheckApplyRedistributeBO checkApplyRedistributeBO = new CheckApplyRedistributeBO();

        // 预约时间
        Date dutyTime = checkApplyRedistributeDIO.getDutyTime();
        if (Objects.nonNull(dutyTime)) {
            List<TagsDRO> tagsDROList = baseCodeService.listBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderConsts.BASE_CODE_MAP_ONE_TYPE_DISTRIBUTE_TIMEOUT, null, null);
            if (CollectionUtil.isNullOrEmpty(tagsDROList)) {
                log.warn("检查是否可以申请改派；查询派单超时控制公共配置失败！一级分类ID:{}", OrderConsts.BASE_CODE_MAP_ONE_TYPE_DISTRIBUTE_TIMEOUT);
                throw new OmsBaseException("查询公共配置失败，请稍后重试。");
            }

            // 派单超时限制（分钟）
            Integer timeoutLimit = tagsDROList.get(0).getTwoTypeId();

            // 预约时间距离当前时间的间隔（分钟）
            long intervalTime = (dutyTime.getTime() - DateUtil.getNow().getTime()) / 60 / 1000;

            // 预约时间已过时 或 距离当前时间小于【派单超时限制（分钟）】
            if (DateUtil.getNow().after(dutyTime) || timeoutLimit > intervalTime) {
                checkApplyRedistributeBO.setDutyTimeExpiredMessage(String.format("预约时间已过时或已不足%d分钟，请与用户重新确定预约时间后再试，谢谢~", timeoutLimit));
            }
        }

        return checkApplyRedistributeBO;
    }

    @Override
    public String verifyWorkStatusForRedistribute(OrderWork orderWork, Integer caller) throws OmsBaseException {

        //2、无：工单结果 = 进行中 & 改派状态 ！= 待改派的改派申请
        if (!Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            return "进行中才可操作";
        }

        //3、订单被改派的次数 ＜ 配置的次数（改派次数配置取公共配置：订单改派次数）
        TagsQuery tagsDIO = new TagsQuery();
        tagsDIO.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        tagsDIO.setOneTypeId(1201);
        ResponseDTO<List<TagsDRO>> codeMapRemote = tagsListRemoteService.listByTagsDIO(tagsDIO);
        if (!codeMapRemote.isSuccess()) {
            return "查询改派次数配置失败，请稍后重试！";
        }
        if (CollectionUtil.isNullOrEmpty(codeMapRemote.getData())) {
            return "无法获取改派次数配置，请稍后重试！";
        }

        Integer confCount = codeMapRemote.getData().get(0).getTwoTypeId();

        OrderChangeRecord changeRecord = orderChangeRecordService.getChangeRecordByOrderId(orderWork.getOrderId());

        if (changeRecord != null && changeRecord.getDistributeCount() >= confCount) {
            return "订单改派次数超限，不可再改派！";
        }

        //3、订单被改派的次数 ＜ 服务商配置的次数（改派次数配置取公共配置：订单改派次数）（后台）
        if (Objects.equals(caller, GlobalConsts.OPERATE_USER_TYPE_STAFF)) {
            Integer companyId = orderWork.getManageCompanyId();
            if (NumberUtil.isNullOrZero(companyId)) {
                // 用行政服务商查
                OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderWork.getOrderId());
                companyId = orderDetail.getGridManageCompanyId();
            }

            if (NumberUtil.isNotNullOrZero(companyId)) {

                // 服务商可改派次数
                Integer spConfCount = this.getSpRedistributeCount(companyId);

                // 获取服务商当天改派次数
                String redisKey = String.format(RedisKeyConsts.ORDER_SERVICE_COMPANY_REDISTRIBUTE_COUNT_DAY_KEY, orderWork.getManageCompanyId());
                String redistributeCountStr = redisManager.get(redisKey);
                Integer redistributeCount = 0;
                if (StringUtils.isNotBlank(redistributeCountStr)) {
                    redistributeCount = Integer.valueOf(redistributeCountStr);
                }

                if (changeRecord != null && redistributeCount >= spConfCount) {
                    return "服务商改派次数超限，不可再改派！";
                }
            }
        }
        return null;
    }

    /**
     * 获取服务商的改派次数
     *
     * @param companyId 服务公司Id
     * @return
     */
    private Integer getSpRedistributeCount(Integer companyId) throws OmsBaseException {
        ResponseDTO<SpServProviderDetailDRO> spServProviderDetailResponseDTO = spManageListRemoteService.getSpServiceProviderDetailByKey(companyId);
        if (log.isDebugEnabled()) {
            log.debug("查询服务商详情，入参：{} 出参：{}", companyId, spServProviderDetailResponseDTO);
        }

        SpServProviderDetailDRO spServProviderDetailDRO = spServProviderDetailResponseDTO.getData();
        if (!spServProviderDetailResponseDTO.isSuccess() || Objects.isNull(spServProviderDetailDRO)) {
            log.warn("服务商ID：[{}]，查询服务商详情失败，原因：{}", companyId, spServProviderDetailResponseDTO.getMessage());
            throw new OmsBaseException("查询服务商详情失败");
        }

        // 服务商创建天数
        int diffDays = (int) ((DateUtil.getNowTimestampMillis() - spServProviderDetailDRO.getCreateTime().getTime()) / (1000 * 3600 * 24));

        List<TagsDRO> tagsDROList = baseCodeService.listBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderConsts.BASE_CODE_MAP_ONE_TYPE_SERVICE_COMPANY_REDISTRIBUTE_COUNT, null, null);
        if (CollectionUtil.isNullOrEmpty(tagsDROList)) {
            throw new OmsBaseException("获取新建服务商的【默认改派次数】公共配置失败");
        }

        // 若服务商创建天数小于（二级类型id）30天，则取公共配置的（三级类型id）【服务商可改派次数】
        TagsDRO tagsDRO = tagsDROList.get(0);
        // 天数
        if (diffDays < tagsDRO.getTwoTypeId()) {
            // 改派次数
            return tagsDRO.getThreeTypeId();
        }

        // 否则计算出服务商的改派次数（当月新单+返修单）
        ResponseDTO<SpRedistributeDRO> spResponseDTO = spManageListRemoteService.getRedistributeBySpId(companyId);
        if (log.isDebugEnabled()) {
            log.debug("获取服务商改派配置，入参：{} 出参：{}", companyId, spResponseDTO);
        }

        SpRedistributeDRO spDRO = spResponseDTO.getData();
        if (!spResponseDTO.isSuccess() || Objects.isNull(spDRO)) {
            log.warn("服务商ID：[{}]，获取服务商改派配置失败，原因：{}", companyId, spResponseDTO.getMessage());
            throw new OmsBaseException("获取服务商改派配置失败");
        }

        // 可改派的次数占单量的百分比
        BigDecimal percent = new BigDecimal(spDRO.getRedistributeNum()).multiply(BigDecimal.valueOf(0.01), MathContext.UNLIMITED);

        // 计算出服务商的改派次数（当月新单+返修单）
        return this.calculateSpRedistributeCount(companyId, spDRO.getRedistribute(), percent);
    }

    /**
     * 计算出服务商的改派次数（当月新单+返修单）
     * 每日在运营后台改派工单的次数，不大于 【xx（新单+返修单的单量）】的 【xx】 %
     * <p>
     * 例：前七日的单量 * 百分比 = 本服务商可改派的次数
     *
     * @param companyId    服务公司Id
     * @param timeType     时间类型：1.前7日平均 2.昨日 3.今日
     * @param countPercent 可改派的次数占单量的百分比
     * @return
     */
    private Integer calculateSpRedistributeCount(Integer companyId, Integer timeType, BigDecimal countPercent) throws OmsBaseException {
        if (log.isDebugEnabled()) {
            log.debug("campanyId: {}，timeType：{}，countPercent：{}", companyId, timeType, countPercent);
        }

        // 1. 取得改派时间枚举对象
        SpRedistributeDateEnum spRedistributeDate = SpRedistributeDateEnum.getEnumByCode(timeType);
        if (Objects.isNull(spRedistributeDate)) {
            log.warn("获取该服务商的改派时间失败，时间类型：【{}】", timeType);
            throw new OmsBaseException("获取该服务商的改派时间失败");
        }

        // 过滤条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                // 服务公司ID
                .filter(QueryBuilders.termQuery("manageCompanyId", companyId))
                // 新单，返修单
                .filter(QueryBuilders.termsQuery("type", Lists.newArrayList(OrderConsts.ORDER_TYPE_NEW, OrderConsts.ORDER_TYPE_REWORK)))
                // 下单时间
                .filter(QueryBuilders.rangeQuery("inputTime")
                        .from(DateUtil.toString(spRedistributeDate.getStartTime()))
                        .to(DateUtil.toString(spRedistributeDate.getEndTime())));

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(queryBuilder)
                .withPageable(Pageable.unpaged()).build();

        Long dbCount = orderWorkEsBService.countByQuery(build);

        if (log.isDebugEnabled()) {
            log.debug("【{}】服务公司在 {} ~ {} 时的单量为: {}", companyId, DateUtil.toString(spRedistributeDate.getStartTime()),
                    DateUtil.toString(spRedistributeDate.getEndTime()), dbCount);
        }

        if (NumberUtil.isNullOrZero(dbCount)) {
            return 0;
        }

        BigDecimal orderCount = new BigDecimal(dbCount);
        if (Objects.equals(SpRedistributeDateEnum.SEVEN_DAYS_BEFORE.getCode(), timeType)) {
            // 前7天单量的平均值（向上取整）
            orderCount = orderCount.divide(new BigDecimal(7), RoundingMode.UP);
            if (log.isDebugEnabled()) {
                log.debug("前7天单量的平均值（向上取整）：{}", orderCount);
            }

        }

        // 3. 计算得出服务商可改派的次数（单量 * 百分比 = 本服务商可改派的次数）
        return orderCount.multiply(countPercent).setScale(0, RoundingMode.UP).intValue();
    }

    @Override
    public AMISListData<ApplyItemDRO> listApplyByQuery(ManagerAuditQuery query) throws OmsBaseException {

        log.info("staffListRemoteService.getStaffByDingTalkId params={}", query.getDingTalkId());
        ResponseDTO<StaffDRO> staffResponseDTO = staffListRemoteService.getStaffByDingTalkId(query.getDingTalkId());
        log.info("staffListRemoteService.getStaffByDingTalkId result={}", JSON.toJSONString(staffResponseDTO));

        if (staffResponseDTO.isSuccess() && Objects.isNull(staffResponseDTO.getData())) {
            throw new OmsBaseException("无法获取审核人信息，请稍后重试");
        }
        StaffDRO staff = staffResponseDTO.getData();

        Integer supervisorId = 0;

        if(Objects.equals(staff.getType(), StaffConsts.STAFF_ROLE_ORDINARY_TYPE)) {
            // 员工
            log.info("listApplyByQuery.getIdByIdentityTypeAndObjectId 入参={}", staffResponseDTO.getData().getStaffId());
            ResponseDTO<Integer> supervisorResponseDTO = engineerSupervisorListRemoteService.getIdByIdentityTypeAndObjectId(2, staffResponseDTO.getData().getStaffId());
            log.info("listApplyByQuery.getIdByIdentityTypeAndObjectId 出参={}", JSON.toJSONString(supervisorResponseDTO));

            if (staffResponseDTO.isSuccess() && Objects.isNull(supervisorResponseDTO.getData())) {
                throw new OmsBaseException("无法获取审核主管信息，请稍后重试");
            }
            supervisorId = supervisorResponseDTO.getData();
        } else if (Objects.equals(staff.getType(), StaffConsts.STAFF_ROLE_MASTER_TYPE)) {
            // 工程师
            // 通过员工ID获取工程师信息
            log.info("listApplyByQuery#getByStaffId 入参 [{}]", staff.getStaffId());
            ResponseDTO<SupervisorDetailDRO> eosResponseDTO = engineerSupervisorListRemoteService.getByStaffId(staff.getStaffId());
            log.info("listApplyByQuery#getByStaffId 出参 [{}]", JSON.toJSONString(eosResponseDTO));
            if (staffResponseDTO.isSuccess() && Objects.isNull(eosResponseDTO.getData())) {
                throw new OmsBaseException("无法获取工程师或审核主管信息，请稍后重试");
            }
            supervisorId = eosResponseDTO.getData().getSupervisorId();
        } else {
            // 其他类型 - 待实现 目前没有
            throw new OmsBaseException("该员工类型暂不支持查询审核信息，请联系技术人员");
        }

        OrderWorkRedistributeApplyQuery applyQuery = new OrderWorkRedistributeApplyQuery();
        applyQuery.setPageIndex(query.getPageIndex());
        applyQuery.setPageSize(query.getPageSize());
        applyQuery.setAuditerId(Long.valueOf(supervisorId));
        if (!Objects.equals(query.getAuditStatus(), 2)) {
            // 待审核
            applyQuery.setAuditStatus(RedistributeAuditStatusEnum.WAIT_AUDIT.getCode());
            applyQuery.setRedistributeStatus(RedistributeStatusEnum.WAIT_REDISTRIBUTE.getCode());
        } else {
            // 其他状态
            applyQuery.setAuditStatus(null);
            applyQuery.setNoAuditStatus(RedistributeAuditStatusEnum.WAIT_AUDIT.getCode());
        }

        AMISListData<ApplyItemDRO> amisListData = new AMISListData<>();

        // 数量
        Integer count = orderWorkRedistributeApplyService.countByQueryForEngineerManager(applyQuery);
        amisListData.setTotal(count);
        if (NumberUtil.isNullOrZero(count)) {
            amisListData.setItems(Lists.newArrayList());
            return amisListData;
        }

        // 内容
        List<OrderWorkRedistributeApply> applyList = orderWorkRedistributeApplyService.listApplyForEngineerManager(applyQuery);

        List<ApplyItemDRO> applyItemDROList = applyList.stream().map(apply -> {
            ApplyItemDRO applyItemDRO = BeanMapper.map(apply, ApplyItemDRO.class);
            applyItemDRO.setAuditStatusName(RedistributeAuditStatusEnum.getEnumDesc(apply.getAuditStatus()));

            return applyItemDRO;
        }).collect(Collectors.toList());

        amisListData.setItems(applyItemDROList);

        return amisListData;
    }

    @Override
    public ApplyDetailDRO getApplyById(Long redistributeId) throws OmsBaseException {
        Assert.notNull(redistributeId, "改派申请ID不能为空");

        OrderWorkRedistributeApply apply = orderWorkRedistributeApplyService.selectByPrimaryKey(redistributeId);
        if (Objects.isNull(apply)) {
            throw new OmsBaseException("改派申请不存在");
        }

        ConfOrderDistributeReasonBO reasonBO = confOrderDistributeReasonBService.getConfOrderDistributeReasonById(apply.getReasonId());

        ApplyDetailDRO detailDRO = new ApplyDetailDRO();
        detailDRO.setRedistributeId(apply.getRedistributeId());

        if (Objects.equals(apply.getApplyUserType(), GlobalConsts.OPERATE_USER_TYPE_MASTER)
                && Objects.equals(reasonBO.getEngineerRedistributeStep().getRedistributeType(), ConfRedistributeTypeEnum.SPECIFY.getCode())) {
            detailDRO.setNeedCheckedEngineer(GlobalConsts.YES);
        } else if (Objects.equals(apply.getApplyUserType(), GlobalConsts.OPERATE_USER_TYPE_SYSTEM)
                && Objects.equals(reasonBO.getSystemRedistributeStep().getRedistributeType(), ConfRedistributeTypeEnum.SPECIFY.getCode())) {
            detailDRO.setNeedCheckedEngineer(GlobalConsts.YES);
        }

        // 处理订单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(apply.getOrderId(), apply.getWorkId());
        ApplyWorkDetailDRO workDetail = BeanMapper.map(orderWork, ApplyWorkDetailDRO.class);

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(apply.getOrderId());
        BeanMapper.copy(orderDetail, workDetail);

        OrderProduct orderProduct = orderProductService.listOrderProductByOrderId(apply.getOrderId()).get(0);
        BeanMapper.copy(orderProduct, workDetail);

        // 手机号加密
        workDetail.setSecretTelephone(MobileUtil.formatHideTel(workDetail.getTelephone()));
        if (StringUtil.isNotBlank(workDetail.getTelephone2())) {
            workDetail.setSecretTelephone2(MobileUtil.formatHideTel(workDetail.getTelephone2()));
        }
        if (StringUtil.isNotBlank(workDetail.getTelephone3())) {
            workDetail.setSecretTelephone3(MobileUtil.formatHideTel(workDetail.getTelephone3()));
        }
        detailDRO.setWorkDetail(workDetail);

        // 改派信息
        ApplyRedistributeDetailDRO redistributeDetail = BeanMapper.map(apply, ApplyRedistributeDetailDRO.class);
        if (Objects.equals(apply.getApplyUserType(), GlobalConsts.OPERATE_USER_TYPE_MASTER)) {
            // 工程师提交改派
            redistributeDetail.setApplyEngineerId(apply.getApplyUserId());
            redistributeDetail.setApplyEngineerName(apply.getApplyUser());

        } else {
            // 非工程师申请，放入源工程师信息 从快照中取
            OrderWorkRedistributeInfo info = orderWorkRedistributeInfoService.findRedistributeInfoById(apply.getRedistributeId());

            // 工程师提交改派
            redistributeDetail.setApplyEngineerId(info.getMasterId());
            redistributeDetail.setApplyEngineerName(info.getMasterName());
        }

        // 处理预约时间
        if (Objects.isNull(redistributeDetail.getDutyTime())) {
            redistributeDetail.setDutyTime(orderWork.getDutyTime());
        }

        // 获取手机号，为了防止工程师已被修改，去engineer服务获取
        log.info("getApplyById#getEngineerMobileInfoById 入参 [{}]",redistributeDetail.getApplyEngineerId().intValue());
        ResponseDTO<ForeignEngineerMobileInfoDRO> engineerResponse = engineerListRemoteService.getEngineerMobileInfoById(redistributeDetail.getApplyEngineerId().intValue());
        log.info("getApplyById#getEngineerMobileInfoById 出参 [{}]",JSON.toJSONString(engineerResponse));
        if (!engineerResponse.isSuccess()) {
            throw new OmsBaseException("获取申请工程师信息失败，请稍后重试");
        }
        redistributeDetail.setApplyEngineerPhone(engineerResponse.getData().getMobile());

        redistributeDetail.setAuditStatusName(RedistributeAuditStatusEnum.getEnumDesc(apply.getAuditStatus()));

        // 处理 照片、音频、视频
        if (StringUtils.isNotBlank(apply.getAttachmentUrls())) {
            try {
                List<RedistributeAttachmentDTO> attachmentList = JSON.parseArray(apply.getAttachmentUrls(), RedistributeAttachmentDTO.class);

                // 转换
                attachmentList.forEach(attachment -> {
                    ArrayList<String> attachmentSrcList = Lists.newArrayList(attachment.getUrl().split(","));

                    if (Objects.equals(attachment.getType(), OrderAttachmentCategoryTypeEnum.PICTURE.getCode())) {
                        redistributeDetail.setImageSrcs(attachmentSrcList);
                    } else if (Objects.equals(attachment.getType(), OrderAttachmentCategoryTypeEnum.VIDEO.getCode())) {
                        redistributeDetail.setVideoSrcs(attachmentSrcList);
                    } else if (Objects.equals(attachment.getType(), OrderAttachmentCategoryTypeEnum.AUDIO.getCode())) {
                        redistributeDetail.setAudioSrcs(attachmentSrcList);
                    }

                });

            } catch (Exception e) {
                log.warn("OrderWorkRedistributeListBService#getApplyById redistributeId={} attachmentUrls={} message={}",
                        apply.getRedistributeId(), apply.getAttachmentUrls(), e.getMessage());
            }

        } else if (StringUtils.isNotBlank(apply.getImageSrc())) {
            List<String> imgSrcs = Arrays.stream(apply.getImageSrc().split(",")).filter(StringUtils::isNotBlank).collect(Collectors.toList());
            redistributeDetail.setImageSrcs(imgSrcs);
        }

        detailDRO.setRedistributeDetail(redistributeDetail);

        return detailDRO;
    }

    @Override
    public List<EngineerWorkRedistributeDRO> listGrabWorkByQuery(RedistributeWorkQuery redistributeWorkQuery) {
        Assert.notNull(redistributeWorkQuery.getMasterId(), "工程师ID不能为空");
        OrderWorkRedistributeMaster query = new OrderWorkRedistributeMaster();
        query.setMasterId(redistributeWorkQuery.getMasterId());
        query.setStatus(GlobalConsts.YES);
        List<OrderWorkRedistributeMaster> masterOrderList = orderWorkRedistributeMasterService.selectByQuerySrcMaster(query);

        List<EngineerWorkRedistributeDRO> orderList = Lists.newArrayListWithCapacity(masterOrderList.size());

        if (CollectionUtil.isNullOrEmpty(masterOrderList)) {
            return orderList;
        }

        // 查询相关派单申请
        List<Long> orderIdList = masterOrderList.stream()
                .map(OrderWorkRedistributeMaster::getOrderId).collect(Collectors.toList());
        OrderWorkRedistributeApplyQuery applyQuery = new OrderWorkRedistributeApplyQuery();
        applyQuery.setOrderIdList(orderIdList);
        applyQuery.setRedistributeStatus(RedistributeStatusEnum.WAIT_REDISTRIBUTE.getCode());
        List<OrderWorkRedistributeApply> applyList = orderWorkRedistributeApplyService.listByQuery(applyQuery);
        Map<Long, OrderWorkRedistributeApply> applyMap = applyList.stream().collect(Collectors.toMap(OrderWorkRedistributeApply::getOrderId, Function.identity(), (e1, e2) -> e1));


        // 查询订单信息
        OrderWorkQuery esQuery = new OrderWorkQuery();
        esQuery.setOrderIdList(orderIdList);
        esQuery.setWorkType(Arrays.asList(OrderConsts.ORDER_TYPE_NEW, OrderConsts.ORDER_TYPE_REWORK));
        esQuery.setPageSize(10000);
        esQuery.setIncludes(Arrays.asList("id", "orderId", "productInfo", "dutyTime", "contact.fullAddress", "contact.location"));
        List<EsOrderWork> esOrderWorkList = orderWorkListBService.listPageOrderWorkByQuery(esQuery);

        orderEncryptService.batchDecryptEsOrderWork(esOrderWorkList, EncryptFieldTypeEnum.USER_FULLADDRESS);// 解密完整地址
        Map<Long, EsOrderWork> orderWorkMap = esOrderWorkList.stream()
                .collect(Collectors.toMap(EsOrderWork::getOrderId, Function.identity(), (e1, e2) -> e1));

        Long version = System.currentTimeMillis();

        orderIdList.forEach(orderId -> {
            // 从工单中获取数据
            EsOrderWork orderWork = orderWorkMap.get(orderId);
            if (Objects.isNull(orderWork)) {
                return;
            }

            EngineerWorkRedistributeDRO orderDRO = new EngineerWorkRedistributeDRO();
            orderDRO.setOrderId(orderId);
            orderDRO.setWorkId(orderWork.getId());
            orderDRO.setProductInfo(orderWork.getProductInfo());
            orderDRO.setDutyTime(orderWork.getDutyTime());
            orderDRO.setAddress(orderWork.getContact().getFullAddress());
            orderDRO.setGrabVersion(version);

            // 从改派申请中获取数据
            OrderWorkRedistributeApply apply = applyMap.get(orderId);
            if (Objects.isNull(apply)) {
                return;
            }

            orderDRO.setDutyTime(apply.getDutyTime());

            Double latitude = null;
            Double longitude = null;
            if (StringUtils.isNotBlank(orderWork.getContact().getLocation())) {
                String[] arr = orderWork.getContact().getLocation().split(",");
                latitude = Double.valueOf(arr[0]);
                longitude = Double.valueOf(arr[1]);
            }

            if (NumberUtil.isNotNullOrZero(apply.getLatitude()) && NumberUtil.isNotNullOrZero(apply.getLongitude())) {
                latitude = apply.getLatitude();
                longitude = apply.getLongitude();
            }
            if (Objects.nonNull(redistributeWorkQuery.getLatitude())
                    && NumberUtil.isNotNullOrZero(latitude)
                    && NumberUtil.isNotNullOrZero(longitude)) {
                double distance = BaiduMapUtil.getDistance(redistributeWorkQuery.getLatitude(), redistributeWorkQuery.getLongitude(),
                        latitude, longitude);
                orderDRO.setDistance(String.valueOf(distance));
            }

            // 抢单类型：求助抢单
            orderDRO.setGrabType(GlobalConsts.YES);

            orderList.add(orderDRO);
        });

        return orderList;
    }

    @Override
    public List<EngineerDRO> listRedistributeEngineer(Long orderId, Long workId, Date dutyTime) {
        Assert.notNull(orderId, "订单号不能为空");
        Assert.notNull(workId, "工单号不能为空");

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderId);

        if (Objects.nonNull(dutyTime)) {
            orderWork.setDutyTime(dutyTime);
        }

        List<ZsOrderDistributeVO> masterList = zsDistributeWorkBService.getRedistributeMasterList(orderWork, orderDetail);

        List<EngineerDRO> resultList = Lists.newArrayList();

        if (CollectionUtil.isNullOrEmpty(masterList)) {
            return resultList;
        }
        resultList = masterList.stream().map(master -> {
            EngineerDRO engineer = BeanMapper.map(master, EngineerDRO.class);
            engineer.setEngineerId(master.getMasterId());
            engineer.setEngineerName(master.getMasterName());
            return engineer;
        }).collect(Collectors.toList());


        return resultList;
    }

    @Override
    public List<EngineerDRO> listRedistributeEngineer(EngineerRedistributeQuery query) throws OmsBaseException {
        Assert.notNull(query.getOrderId(), "订单号不能为空");
        Assert.notNull(query.getWorkId(), "工单号不能为空");

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(query.getOrderId(), query.getWorkId());
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(query.getOrderId());

        if (Objects.nonNull(query.getDutyTime())) {
            orderWork.setDutyTime(query.getDutyTime());
        }

        if (NumberUtil.isNullOrZero(query.getCategId())
                && NumberUtil.isNotNullOrZero(query.getProductId())
                && !Objects.equals(query.getProductId(), orderWork.getProductId())) {

            ProductBaseQuery productBaseQuery = ProductBaseQuery
                    .builder()
                    .defaultType(1)
                    .productId(query.getProductId())
                    .showType(BaseProductConsts.ERP_SHOW_TYPE)
                    .cityId(orderWork.getCityId())
                    .channelId(orderWork.getChannelId())
                    .bizType(orderWork.getBizType())
                    .build();
            ResponseDTO<List<ProductBaseDRO>> responseDTO = productForeignListRemoteService.listBaseDROByQuery(productBaseQuery);
            if (log.isDebugEnabled()) {
                log.debug("#getProductList 入参：{} ,出参：{}", productBaseQuery, responseDTO);
            }
            if (!responseDTO.isSuccess() || CollectionUtil.isNullOrEmpty(responseDTO.getData())) {
                throw new OmsBaseException("获取产品信息失败");
            }
            ProductBaseDRO productBaseDRO = responseDTO.getData().get(0);
            query.setProductId(productBaseDRO.getProductId());
            query.setServCategId(productBaseDRO.getServCategId());
            query.setCategId(productBaseDRO.getCategId());
        }

        List<ZsOrderDistributeVO> masterList = zsDistributeWorkBService.getGridDistributeMasterList(orderWork, orderDetail, query);

        List<EngineerDRO> resultList = Lists.newArrayList();

        if (CollectionUtil.isNullOrEmpty(masterList)) {
            return resultList;
        }
        resultList = masterList.stream().map(master -> {
            EngineerDRO engineer = BeanMapper.map(master, EngineerDRO.class);
            engineer.setEngineerId(master.getMasterId());
            engineer.setEngineerName(master.getMasterName());
            return engineer;
        }).collect(Collectors.toList());


        return resultList;
    }

    @Override
    public OrderWorkRedistributeStatusDRO getRedistributeStatusById(Long redistributeId) {
        Assert.notNull(redistributeId, "改派申请ID不能为空");
        OrderWorkRedistributeApply apply = orderWorkRedistributeApplyService.selectByPrimaryKey(redistributeId);
        return BeanMapper.map(apply, OrderWorkRedistributeStatusDRO.class);
    }
}
